home *** CD-ROM | disk | FTP | other *** search
Wrap
/* File: ntfs.c Copyright (C) 1998-2004 Christophe GRENIER <grenier@cgsecurity.org> This software is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /*define NTFS_DEBUG 1 */ #define NTFS_GETU8(p) (*(const __u8*)(p)) #define NTFS_GETU16(p) (*(const __u16*)(p)) #define NTFS_GETU32(p) (*(const __u32*)(p)) #define NTFS_GETU64(p) (*(const __u64*)(p)) #include <stdio.h> #include <string.h> #include <ctype.h> #include "types.h" #include "common.h" #include "intrface.h" #include "ntfs.h" #include "fnctdsk.h" #include "lang.h" static int create_ntfs_boot_sector(t_param_disk *disk_car,const t_diskext *partition, const int part_type, const int interface, const __u8 cluster_size, const __u64 mft_cluster, const __u64 mftbak_cluster, const __s32 clusters_frs, const __s32 clusters_record); static int dump_ntfs_info(const struct ntfs_boot_sector *ntfs_header); static int dump_2ntfs_info(const struct ntfs_boot_sector *nh1, const struct ntfs_boot_sector *nh2); static int ntfs_read_MFT(t_param_disk *disk_car, t_diskext *partition, const struct ntfs_boot_sector*ntfs_header,const int my_type,const int debug, const int dump_ind); static int ntfs_find_mft(t_param_disk *disk_car, t_diskext *partition, const int debug, const int interface); static int ntfs_get_attr(const char *mft_record, const int my_type, t_diskext *partition, const char *end, const int debug, const int dump_ind, const char*file_name_to_find); int check_NTFS(t_param_disk *disk_car,t_diskext *partition,const int debug,const int dump_ind) { unsigned char buffer[SECTOR_SIZE]; if(disk_car->read(disk_car,1, &buffer, partition->lba)!=0) { return 1; } if(test_NTFS(disk_car,(struct ntfs_boot_sector*)&buffer,partition,debug,dump_ind)!=0) return 1; set_NTFS_info(disk_car,(struct ntfs_boot_sector*)&buffer,partition,debug,dump_ind); return 0; } int recover_NTFS(t_param_disk *disk_car, const struct ntfs_boot_sector*ntfs_header,t_diskext *partition,const int debug, const int dump_ind, const int backup) { if(test_NTFS(disk_car,ntfs_header,partition,debug,dump_ind)!=0) return 1; partition->part_size=le64(ntfs_header->sectors_nbr)+1; partition->part_type=(unsigned char)P_NTFS; if(backup) { partition->boot_sector=partition->part_size-1; partition->lba-=partition->part_size-1; } set_NTFS_info(disk_car,ntfs_header,partition,debug,dump_ind); return 0; } int set_NTFS_info(t_param_disk *disk_car, const struct ntfs_boot_sector*ntfs_header,t_diskext *partition,const int debug, const int dump_ind) { partition->name[0]='\0'; return ntfs_read_MFT(disk_car, partition, ntfs_header,0x60,debug,dump_ind); } int test_NTFS(const t_param_disk *disk_car,const struct ntfs_boot_sector*ntfs_header, t_diskext *partition,const int debug, const int dump_ind) { const char*buffer=(const char*)ntfs_header; if(le16(ntfs_header->marker)==0xAA55) { if(memcmp(ntfs_header->system_id,"NTFS",4)==0) { if((ntfs_header->reserved>0) || (ntfs_header->fats>0) || (ntfs_header->dir_entries[0]!=0) || (ntfs_header->dir_entries[1]!=0) || (ntfs_header->sectors[0]!=0) || (ntfs_header->sectors[1]!=0) || (ntfs_header->fat_length!=0) || (ntfs_header->total_sect!=0) || (ntfs_header->cluster_size==0)) return 1; if((debug!=0) || (dump_ind!=0)) { ecrit_rapport("NTFS at %u/%u/%u\n", LBA2cylinder(disk_car,partition->lba),LBA2head(disk_car,partition->lba),LBA2sector(disk_car,partition->lba)); } if((dump_ind!=0)&&(debug!=0)) dump(stdscr,buffer,SECTOR_SIZE); partition->upart_type=UP_NTFS; return 0; } } /* fin marqueur de fin :)) */ return 1; } /* */ static int ntfs_get_attr(const char *mft_record, const int my_type, t_diskext *partition, const char *end, const int debug, const int dump_ind, const char*file_name_to_find) { const char *attr_record; int attr_type; /* Only check for magic DWORD here, fixup should have happened before */ if(memcmp(mft_record,"FILE",4)) return 2; /* NTFS_RECORD_TYPES == magic_FILE ?*/ if(NTFS_GETU16(mft_record + 0x14)%8!=0) return 2; if(NTFS_GETU16(mft_record + 0x14)<42) /* sizeof(MFT_RECORD)>=42 */ return 2; /* aff_buffer(BUFFER_ADD,"FILE\n"); */ /* aff_buffer(BUFFER_ADD,"seq nbr %lu ",NTFS_GETU16(mft_record+0x10)); */ /* aff_buffer(BUFFER_ADD,"main MFT record %lu ",NTFS_GETU64(mft_record+0x20)); */ /* location of first attribute */ attr_record= mft_record + NTFS_GETU16(mft_record + 0x14); while(1) { /* Resident attributes attr_len>=24(0x18), non resident is bigger */ unsigned int attr_len; if(attr_record+0x18>=end) { ecrit_rapport("ntfs_get_attr attr_record+0x18>=end\n"); return 2; } attr_type=NTFS_GETU32(attr_record); if(attr_type==-1) /* attribute list end with type -1 */ return 0; /* ecrit_rapport("attr_type=%x\n",attr_type); */ attr_len=NTFS_GETU16(attr_record+4); if((attr_len%8!=0)||(attr_len<0x18)) { ecrit_rapport("ntfs_get_attr attr_type=%x attr_len=%u (attr_len%%8!0)||(attr_len<0x18)\n",attr_type,attr_len); return 2; } if(dump_ind) { WINDOW *window=newwin(0,0,0,0); /* full screen */ keypad(window, TRUE); /* Need it to get arrow key */ aff_copy(window); dump(window,attr_record,attr_len); delwin(window); #ifdef DJGPP wredrawln(stdscr,0,stdscr->_maxy); /* redrawwin def is boggus in pdcur24 */ #else redrawwin(stdscr); /* stdscr has been corrupted by window */ #endif } if(NTFS_GETU8(attr_record+8)==0) /* attribute is resident */ { unsigned int attr_value_length=NTFS_GETU16(attr_record+0x10); unsigned int attr_value_offset=NTFS_GETU16(attr_record+0x14); const char *attr_list_entry=attr_record+attr_value_offset; if(attr_value_offset%8!=0) { ecrit_rapport("ntfs_get_attr attr_value_offset=%u (%%8!=0)\n",attr_value_offset); return 2; } if(attr_list_entry+26>=end) { ecrit_rapport("ntfs_get_attr attr_list_entry+26=%p, end=%p\n",attr_list_entry+26,end); return 2; } /* We found the attribute type. Is the name correct, too? */ #ifdef NTFS_DEBUG ecrit_rapport("pos=%p type %x attr_list_entry %p\n",attr_record-mft_record,attr_type,attr_list_entry-mft_record); aff_buffer(BUFFER_ADD,"type %02X\n",attr_type); #endif if((attr_value_offset+attr_value_length>attr_len) || (attr_list_entry+attr_len >= end)) { ecrit_rapport("ntfs_get_attr "); return 2; } if((attr_type==my_type)&&(attr_value_offset!=0)) { switch(attr_type) { case 0x30: /* AT_FILE_NAME */ { const char *file_name_attr=attr_list_entry; unsigned int file_name_length; const char *name_it; if(file_name_attr+0x42>=end) return 2; file_name_length=NTFS_GETU8(file_name_attr+0x40); /* size in unicode char */ if(file_name_attr+0x42+2*file_name_length>=end) return 2; { char file_name[file_name_length+1]; unsigned int i; /* aff_buffer(BUFFER_ADD,"MFT record nbr %lu ",NTFS_GETU64(file_name_attr)); */ for(name_it=file_name_attr+0x42,i=0;i<file_name_length; name_it+=2,i++) file_name[i]=*name_it; file_name[i]='\0'; if(file_name_to_find!=NULL) { if(debug) { ecrit_rapport("file_name=%s, %u\n",file_name,NTFS_GETU32(file_name_attr)); } if(strcmp(file_name_to_find,file_name)==0) return 1; else return 2; } else aff_buffer(BUFFER_ADD,"%s\n",file_name); } } break; case 0x60: /* AT_VOLUME_NAME */ { unsigned int volume_name_length=attr_value_length; const char *name_it; char *dest=partition->name; volume_name_length/=2; /* Unicode */ if(volume_name_length>sizeof(partition->name)-1) volume_name_length=sizeof(partition->name)-1; for(name_it=attr_list_entry;(volume_name_length>0) && (*name_it!='\0') && (name_it[1]=='\0'); name_it+=2,volume_name_length--) *dest++=*name_it; *dest++='\0'; /* 27 january 2003: Correct a bug found by Andreas du Plessis-Denz */ } return 1; } } } attr_record+=attr_len; } } #ifdef OLD int dir_ntfs(WINDOW *window,t_param_disk *disk_car,t_diskext *partition) { unsigned char buffer[SECTOR_SIZE]; int debug=0; int dump_ind=0; aff_buffer(BUFFER_RESET,"Q"); wmove(window,5,0); aff_part(window,AFF_PART_NL,disk_car,partition); ecrit_rapport("\n"); aff_part_rapport(disk_car,partition); if(disk_car->read(disk_car,1, &buffer, partition->lba+partition->boot_sector)!=0) { return 1; } if(test_NTFS(disk_car,(struct ntfs_boot_sector*)&buffer,partition,debug,dump_ind)!=0) { aff_buffer(BUFFER_ADD,"Invalid NTFS data\n"); } else ntfs_read_MFT(disk_car,partition,(struct ntfs_boot_sector*)&buffer,0x30,0,0); aff_buffer(BUFFER_DISPLAY,"Q",window); return 0; } #endif static int ntfs_read_MFT(t_param_disk *disk_car, t_diskext *partition, const struct ntfs_boot_sector*ntfs_header,const int my_type,const int debug, const int dump_ind) { unsigned char *buffer; unsigned char *attr; dword mft_pos; unsigned int mft_recordsize; mft_pos=partition->lba+ntfs_header->reserved+ntfs_header->mft_cluster*ntfs_header->cluster_size; if(ntfs_header->clusters_record>0) mft_recordsize=ntfs_header->cluster_size*ntfs_header->clusters_record; else mft_recordsize=1<<(-ntfs_header->clusters_record); buffer=(unsigned char *)MALLOC(mft_recordsize*SECTOR_SIZE); #ifdef NTFS_DEBUG ecrit_rapport("NTFS cluster size = %u\n",ntfs_header->cluster_size); ecrit_rapport("NTFS MFT_record_size = %u\n",mft_recordsize); ecrit_rapport("NTFS MFT cluster = %lu\n",ntfs_header->mft_cluster); #endif if(disk_car->read(disk_car,mft_recordsize, buffer, mft_pos)!=0) { ecrit_rapport(msg_ROOT_CLUSTER_RERR); FREE(buffer); return 1; } attr=buffer; while(attr+0x30<=(buffer+mft_recordsize*SECTOR_SIZE)) { int res=ntfs_get_attr(attr,my_type,partition,buffer+mft_recordsize*SECTOR_SIZE,debug,dump_ind,NULL); if((res>0)|| (NTFS_GETU32(attr + 0x1C)<0x30)) { FREE(buffer); return res; } attr+= NTFS_GETU32(attr + 0x1C); } FREE(buffer); return 0; } int is_ntfs(const int part_type) { switch(part_type) { case P_NTFS: case P_NTFSH: return 1; } return 0; } #ifdef NEW static int create_ntfs_boot_sector(t_param_disk *disk_car,const t_diskext *partition, const int part_type, const int interface, const __u8 cluster_size, const __u64 mft_cluster, const __u64 mftbak_cluster, const __s32 clusters_frs, const __s32 clusters_record) { unsigned char orgboot[SECTOR_SIZE]; unsigned char newboot[SECTOR_SIZE]; struct ntfs_boot_sector *org_ntfs_header=(struct ntfs_boot_sector *)&orgboot; struct ntfs_boot_sector *ntfs_header=(struct ntfs_boot_sector *)&newboot; int error=0; if(disk_car->read(disk_car,1, &orgboot, partition->lba)!=0) { ecrit_rapport(msg_CHKFAT_RERR); return 1; } memcpy(&newboot,&orgboot,SECTOR_SIZE); memcpy(ntfs_header->system_id,"NTFS ",8); ntfs_header->sector_size[0]=SECTOR_SIZE & 0xFF; ntfs_header->sector_size[1]=SECTOR_SIZE>>8; ntfs_header->cluster_size=cluster_size; ntfs_header->reserved=0; ntfs_header->fats=0; ntfs_header->dir_entries[0]=0; ntfs_header->dir_entries[1]=0; ntfs_header->sectors[0]=0; ntfs_header->sectors[1]=0; ntfs_header->media=0xF8; ntfs_header->fat_length=0; ntfs_header->secs_track=disk_car->CHS.sector; ntfs_header->heads=disk_car->CHS.head+1; if(partition->status==STATUS_LOG) ntfs_header->hidden=63; else ntfs_header->hidden=partition->lba; ntfs_header->total_sect=0; ntfs_header->sectors_nbr=partition->part_size-1; ntfs_header->mft_cluster=mft_cluster; ntfs_header->mftbak_cluster=mftbak_cluster; ntfs_header->clusters_frs=clusters_frs; ntfs_header->clusters_record=clusters_record; ntfs_header->marker=0xAA55; if(memcmp(newboot,orgboot,SECTOR_SIZE)) { ecrit_rapport(" New / Current boot sector"); dump_2ntfs_rapport(ntfs_header,org_ntfs_header); ecrit_rapport("Extrapolated boot sector and current boot sector are different.\n"); } else { ecrit_rapport("Extrapolated boot sector and current boot sector are identical.\n"); } if(error) ecrit_rapport("Bad extrapolation.\n"); /* */ if(interface) { struct MenuItem menuSaveBoot[]= { { 'Q',"Quit","Quit this section"}, { 'W', "Write","Write boot"}, { 0, NULL, NULL } }; const char *options="Q"; int do_write=0; aff_copy(stdscr); wmove(stdscr,4,0); wdoprintf(stdscr,"%s",disk_car->description(disk_car)); mvwaddstr(stdscr,6,0,msg_PART_HEADER2); wmove(stdscr,7,0); aff_part(stdscr,AFF_PART_ORDER,disk_car,partition); wmove(stdscr,8,0); if(memcmp(newboot,orgboot,SECTOR_SIZE)) /* Only compare the first sector */ { options="WQ"; dump_2ntfs_info(ntfs_header, org_ntfs_header); dump_2ntfs_rapport(ntfs_header, org_ntfs_header); wdoprintf(stdscr,"Extrapolated boot sector and current boot sector are different.\n"); if(error) ecrit_rapport("Warning: Extrapolated boot sector have incorrect values.\n"); } else { dump_ntfs_info(ntfs_header); dump_ntfs_rapport(ntfs_header); wdoprintf(stdscr,"Extrapolated boot sector and current boot sector are identical.\n"); } switch(toupper(wmenuSelect(stdscr,INTER_DUMP_Y, INTER_DUMP_X, menuSaveBoot,8,options,MENU_HORIZ | MENU_BUTTON | MENU_ACCEPT_OTHERS, 0))) { case 'W': if(strchr(options,'W')!=NULL) do_write=1; break; } if(do_write!=0 && ask_confirmation("Write new NTFS boot sector, confirm ? (Y/N)")!=0) { ecrit_rapport("Write new boot!\n"); /* Write boot sector and backup boot sector */ if(disk_car->write(disk_car,1, &newboot, partition->lba)) { display_message("Write error: Can't write new NTFS boot sector\n"); } if(disk_car->write(disk_car,1, &newboot, partition->lba+partition->part_size-1)!=0) { display_message("Write error: Can't write new NTFS backup boot sector\n"); } } else ecrit_rapport("Don't write new boot!\n"); } return 0; } #endif static int dump_2ntfs_info(const struct ntfs_boot_sector *nh1, const struct ntfs_boot_sector *nh2) { wdoprintf(stdscr,"cluster_size %u %u\n",nh1->cluster_size,nh2->cluster_size); wdoprintf(stdscr,"mft_cluster %lu %lu\n",(long unsigned int)nh1->mft_cluster,(long unsigned int)nh2->mft_cluster); wdoprintf(stdscr,"mftbak_cluster %lu %lu\n",(long unsigned int)nh1->mftbak_cluster,(long unsigned int)nh2->mftbak_cluster); wdoprintf(stdscr,"clusters_frs %d %d\n",nh1->clusters_frs,nh2->clusters_frs); wdoprintf(stdscr,"clusters_record %d %d\n",nh1->clusters_record,nh2->clusters_record); return 0; } int dump_2ntfs_rapport(const struct ntfs_boot_sector *nh1, const struct ntfs_boot_sector *nh2) { ecrit_rapport("cluster_size %u %u\n",nh1->cluster_size,nh2->cluster_size); ecrit_rapport("mft_cluster %lu %lu\n",(long unsigned int)nh1->mft_cluster,(long unsigned int)nh2->mft_cluster); ecrit_rapport("mftbak_cluster %lu %lu\n",(long unsigned int)nh1->mftbak_cluster,(long unsigned int)nh2->mftbak_cluster); ecrit_rapport("clusters_frs %d %d\n",nh1->clusters_frs,nh2->clusters_frs); ecrit_rapport("clusters_record %d %d\n",nh1->clusters_record,nh2->clusters_record); return 0; } static int dump_ntfs_info(const struct ntfs_boot_sector *ntfs_header) { wdoprintf(stdscr,"cluster_size %u\n",ntfs_header->cluster_size); wdoprintf(stdscr,"mft_cluster %lu\n",(long unsigned int)ntfs_header->mft_cluster); wdoprintf(stdscr,"mftbak_cluster %lu\n",(long unsigned int)ntfs_header->mftbak_cluster); wdoprintf(stdscr,"clusters_frs %d\n",ntfs_header->clusters_frs); wdoprintf(stdscr,"clusters_record %d\n",ntfs_header->clusters_record); return 0; } int dump_ntfs_rapport(const struct ntfs_boot_sector *ntfs_header) { ecrit_rapport("cluster_size %u\n",ntfs_header->cluster_size); ecrit_rapport("mft_cluster %lu\n",(long unsigned int)ntfs_header->mft_cluster); ecrit_rapport("mftbak_cluster %lu\n",(long unsigned int)ntfs_header->mftbak_cluster); ecrit_rapport("clusters_frs %d\n",ntfs_header->clusters_frs); ecrit_rapport("clusters_record %d\n",ntfs_header->clusters_record); return 0; } static int ntfs_find_mft(t_param_disk *disk_car, t_diskext *partition, const int debug, const int interface) { unsigned long int sector; unsigned char buffer[2*SECTOR_SIZE]; int ind_stop=FALSE; for(sector=1;(sector<partition->part_size)&&(ind_stop==FALSE);sector++) { if((interface!=0) &&(sector%200)==0) { wmove(stdscr,9,0); wclrtoeol(stdscr); wdoprintf(stdscr,"Search mft %10lu/%lu",sector,partition->part_size); wrefresh(stdscr); switch(wgetch_nodelay(stdscr)) { case KEY_ENTER: #ifdef PADENTER case PADENTER: #endif case '\n': case '\r': case 's': case 'S': ind_stop=1; break; } } if(disk_car->read(disk_car,2, &buffer, partition->lba+sector)!=0) { return 1; } if(memcmp(buffer,"FILE",4)==0 && (NTFS_GETU16(buffer+ 0x14)%8==0) && (NTFS_GETU16(buffer+ 0x14)>=42)) { int res; res=ntfs_get_attr(buffer,0x30,partition,buffer+2*SECTOR_SIZE,debug,0,"$MFT"); if(res==1) ecrit_rapport("mft at %ld, seq=%u, main=%u res=%d\n",sector,NTFS_GETU8(buffer+0x10),NTFS_GETU32(buffer+0x20),res); } } return 0; } int rebuild_NTFS_BS(t_param_disk *disk_car, t_diskext *partition, const int debug, const int dump_ind,const int interface) { ntfs_find_mft(disk_car,partition,debug,interface); return 0; }